import sys

from encoding_parser import parse_file

def get_name_list(encoding_list):
    name_list = []
    for encoding in encoding_list:
        name = encoding[1]
        if name not in name_list:
            name_list.append(name)
    return name_list

def macro_name(name):
    return 'INSTR_' + name.upper()

def gen_case_class(encoding_list, f):
    trans_table = str.maketrans('x', '?')
    f.write('always @* begin\n')
    f.write('  casez (i_instr)\n')
    for encoding in encoding_list:
        bitpat, name = encoding[:2]
        f.write("    32'b%s: o_instr_class = 1<<`%s;\n" %
                (bitpat.translate(trans_table), macro_name(name)))
    f.write('    default: o_instr_class = 1;\n') # undefined instruction
    f.write('  endcase\n')
    f.write('end\n')

def main():
    (encoding_file_path,) = sys.argv[1:]
    encoding_list = parse_file(encoding_file_path)
    class_name_list = ['und'] + get_name_list(encoding_list)
    with open('instructions.vh', 'w') as f:
        f.write('`define NUM_INSTR %d\n' % len(class_name_list))
        for index, name in enumerate(class_name_list):
            f.write('`define %s %d\n' % (macro_name(name), index))
        f.write('`define INSTR_IRQ %d\n' % len(class_name_list))
    with open('instruction_decoder.v', 'w') as f:
        f.write('''\
`include "instructions.vh"
module instruction_decoder(i_instr, o_instr_class);
input [31:0] i_instr;
output reg [`NUM_INSTR-1:0] o_instr_class;
''')
        gen_case_class(encoding_list, f)
        f.write('endmodule\n')

if __name__ == "__main__":
    main()
